package com.yjymm.edu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yjymm.edu.common.DateTimeUtils;
import com.yjymm.edu.common.MyBeanUtils;
import com.yjymm.edu.common.StringUtils;
import com.yjymm.edu.common.constant.AdminLogConstant;
import com.yjymm.edu.common.constant.UserLogConstant;
import com.yjymm.edu.exception.MyException;
import com.yjymm.edu.mapper.*;
import com.yjymm.edu.model.dto.FetchMoneyDTO;
import com.yjymm.edu.model.dto.FetchResultDTO;
import com.yjymm.edu.model.dto.FetchSearchDTO;
import com.yjymm.edu.model.entity.*;
import com.yjymm.edu.model.vo.FetchVO;
import com.yjymm.edu.service.FetchLogService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author yjymm
 * @since 2021-03-21
 */
@Service
public class FetchLogServiceImpl extends ServiceImpl<FetchLogMapper, FetchLog> implements FetchLogService {

    @Resource
    private AdminLogMapper adminLogMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private MoneyLogMapper moneyLogMapper;

    @Resource
    private UserLogMapper userLogMapper;
    /**
     * 用户发起提现
     *
     * @param fetchMoneyDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertFetch(FetchMoneyDTO fetchMoneyDTO) throws SQLException {
        // 判断提现金额是否大于用户余额
        User user = userMapper.selectById(fetchMoneyDTO.getUid());
        if (user.getBalance().doubleValue() - fetchMoneyDTO.getMoney().doubleValue() < 0){
            throw new MyException("提现失败，提现金额不能大于可用余额");
        }
//        if (user.getBalance() < fetchMoneyDTO.getMoney()) {
//            throw new MyException("提现失败，提现金额不能大于可用余额");
//        }

        // 生成提现单
        FetchLog fetchLog = new FetchLog();
        fetchLog.setResult("发起提现");
        fetchLog.setUid(fetchMoneyDTO.getUid());
        fetchLog.setFetchMoney(fetchMoneyDTO.getMoney());
        fetchLog.setState(0);
        fetchLog.setFetchNum(StringUtils.getRandomString("fetch"));
        int insert = baseMapper.insert(fetchLog);
        if (insert != 1) {
            throw new SQLException("发起失败,稍后重试");
        }

        // 更新用户相关金额
//        user.setBalance(user.getBalance() - fetchMoneyDTO.getMoney());
        user.setBalance(user.getBalance().subtract(fetchMoneyDTO.getMoney()));
//        user.setFreezeBalance(user.getFreezeBalance() + fetchMoneyDTO.getMoney());
        user.setFreezeBalance(user.getFreezeBalance().add(fetchMoneyDTO.getMoney()));
        userMapper.updateById(user);

        // 记录用户账户金额变更
        MoneyLog moneyLog = MoneyLog.builder()
                .uid(fetchMoneyDTO.getUid())
                .money(fetchMoneyDTO.getMoney())
                .createTime(fetchMoneyDTO.getFetchTime())
                .balance(user.getBalance())
                .freezeBalance(user.getFreezeBalance())
                .state(0)
                .description("用户提现")
                .build();
        moneyLogMapper.insert(moneyLog);

        // 生成用户消息
        String log = String.format(UserLogConstant.USER_FETCH_FETCHLOG_NOTICE,
                DateTimeUtils.formatStr(fetchMoneyDTO.getFetchTime()), fetchMoneyDTO.getMoney());
        UserLog userLog = UserLog.builder()
                .createTime(LocalDateTime.now())
                .uid(fetchMoneyDTO.getUid())
                .state(0)
                .description(log)
                .build();
        userLogMapper.insert(userLog);

        // 通知管理员审核
        AdminLog adminLog = new AdminLog();
        String s1 = String.format(AdminLogConstant.USER_FETCH_NOTICE_ADMIN, user.getUsername(),
                user.getId(), user.getRealName() != null ? user.getRealName() : "暂无,",
                DateTimeUtils.formatStr(fetchMoneyDTO.getFetchTime()),
                fetchLog.getFetchMoney());
        adminLog.setDescription(s1);
        adminLog.setCreateTime(LocalDateTime.now());
        adminLog.setLogTime(LocalDateTime.now());
        adminLog.setState(0);
        adminLog.setType(1);
        adminLog.setDeleted(0);

        adminLogMapper.insert(adminLog);
    }

    /**
     * 用户取消提现
     *
     * @param fid
     * @param uid
     */
    @Override
    @Transactional
    public void cancel(Integer fid, Integer uid) {
        FetchLog fetchLog = baseMapper.selectById(fid);
        if (fetchLog == null) {
            throw new MyException("该记录不存在");
        }
        if (fetchLog.getState() == 1 || fetchLog.getState() == 2) {
            throw new MyException("该订单已完成，无需再次操作");
        }
        if (fetchLog.getState() != 0) {
            throw new MyException("订单异常");
        }
        // 取消提现
        fetchLog.setState(3);
        fetchLog.setFinishTime(LocalDateTime.now());
        baseMapper.updateById(fetchLog);

        // 变更用户账户，记录用户账户变动
        User user = userMapper.selectById(uid);
//        user.setBalance(user.getBalance() + fetchLog.getFetchMoney());
//        user.setFreezeBalance(user.getFreezeBalance() - fetchLog.getFetchMoney());
        user.setBalance(user.getBalance().add(fetchLog.getFetchMoney()));
        user.setFreezeBalance(user.getFreezeBalance().subtract(fetchLog.getFetchMoney()));
        userMapper.updateById(user);

        // 通知管理员
        AdminLog adminLog = new AdminLog();
        String s1 = String.format(AdminLogConstant.USER_CANCEL_FETCH_NOTICE, user.getUsername(),
                user.getId(), DateTimeUtils.formatStr(LocalDateTime.now()), fetchLog.getId(),fetchLog.getFetchMoney());
        adminLog.setDescription(s1);

        adminLogMapper.insert(adminLog);

        // 通知用户消息
        String message = String.format(UserLogConstant.USER_CANCEL_FETCH_NOTICE, DateTimeUtils.formatStr(LocalDateTime.now()),
                fetchLog.getId(), fetchLog.getFetchMoney());
        UserLog userLog = UserLog.builder()
                .uid(user.getId())
                .state(0)
                .createTime(LocalDateTime.now())
                .description(message)
                .build();
        userLogMapper.insert(userLog);

        // 记录用户账户金额变更
        MoneyLog moneyLog = MoneyLog.builder()
                .uid(user.getId())
                .money(fetchLog.getFetchMoney())
                .createTime(LocalDateTime.now())
                .balance(user.getBalance())
                .freezeBalance(user.getFreezeBalance())
                .state(0)
                .description("用户取消提现")
                .build();
        moneyLogMapper.insert(moneyLog);


    }

    /**
     * 管理员审核用户提现订单
     *
     * @param fetchResultDTO
     */
    @Override
    public void checkFecthLog(FetchResultDTO fetchResultDTO) {
        //判断订单状态是否正常
        FetchLog fetchLog = baseMapper.selectById(fetchResultDTO.getFid());
        if (fetchLog.getState() == 3) {
            throw new MyException("用户已取消了提现");
        }
        if (fetchLog.getState() == 1 || fetchLog.getState() == 2) {
            throw new MyException("该订单已完成，无需再次操作");
        }
        if (fetchLog.getState() != 0) {
            throw new MyException("订单状态异常");
        }
        User user = userMapper.selectById(fetchLog.getUid());
        // 判断管理员操作
        if (fetchResultDTO.getAdminOpCode() == 0) {
            // 提现审核不通过,恢复用户余额
            user.setBalance(user.getBalance().add(fetchLog.getFetchMoney()));
            user.setFreezeBalance(user.getFreezeBalance().subtract(fetchLog.getFetchMoney()));
            userMapper.updateById(user);

            fetchLog.setResult(UserLogConstant.ADMIN_REJECT_USER_FETCH);
            fetchLog.setFinishTime(LocalDateTime.now());
            fetchLog.setState(2);
            baseMapper.updateById(fetchLog);

            // 用户提示信息
            UserLog userLog = UserLog.builder()
                    .uid(fetchLog.getUid())
                    .state(0)
                    .createTime(LocalDateTime.now())
                    .description(UserLogConstant.ADMIN_REJECT_USER_FETCH)
                    .build();
            userLogMapper.insert(userLog);
            return;
        }

//        user.setBalance(user.getBalance().add(fetchLog.getFetchMoney()));
        user.setFreezeBalance(user.getFreezeBalance().subtract(fetchLog.getFetchMoney()));
        userMapper.updateById(user);

        // 更新提现订单
        fetchLog.setFinishTime(LocalDateTime.now());
        fetchLog.setResult(UserLogConstant.ADMIN_ALLOW_USER_FETCH);
        fetchLog.setState(1);
        baseMapper.updateById(fetchLog);

        // 用户提示信息
        UserLog userLog = UserLog.builder()
                .uid(fetchLog.getUid())
                .state(0)
                .createTime(LocalDateTime.now())
                .description(UserLogConstant.ADMIN_ALLOW_USER_FETCH)
                .build();
        userLogMapper.insert(userLog);
    }

    @Override
    public List<FetchLog> getList(Integer uid) {
        Map<String, Object> map = new HashMap();
        map.put("uid", uid);
        List<FetchLog> fetchLogs = baseMapper.selectByMap(map);
        fetchLogs.sort((x,y) -> {
            return (int) (y.getFetchTime().toEpochSecond(ZoneOffset.of("+8")) - x.getFetchTime().toEpochSecond(ZoneOffset.of("+8")));
        });
        return fetchLogs;
    }

    /**
     * 查询fetchlog
     * @param dto
     * @return
     */
    @Override
    public IPage searchList(FetchSearchDTO dto) {
        QueryWrapper<FetchLog> queryWrapper = new QueryWrapper<>();
        if (dto.getState() != null) {
            queryWrapper.eq("state", dto.getState());
        }
        if (dto.getUid()!=null) {
            queryWrapper.eq("uid", dto.getUid());
        }
        queryWrapper.orderByDesc("fetch_time");
        IPage<FetchLog> fetchLogIPage = baseMapper.selectPage(new Page<>(dto.getPage(), dto.getSize()), queryWrapper);
        IPage<FetchVO> result = new Page<>(dto.getPage(), dto.getSize());
        if (!CollectionUtils.isEmpty(fetchLogIPage.getRecords())) {
            List<FetchVO> fetchVOS = MyBeanUtils.converToList(fetchLogIPage.getRecords(), FetchVO.class);
            for (FetchVO fetchVO : fetchVOS) {
                Integer uid = fetchVO.getUid();
                User user = userMapper.selectById(uid);
                fetchVO.setUser(user);
            }
            result.setRecords(fetchVOS);
        }
        result.setTotal(fetchLogIPage.getTotal());
        result.setPages(fetchLogIPage.getPages());
        return result;
    }

    @Override
    public Integer getCount() {
        QueryWrapper<FetchLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("deleted",0);
        Integer integer = baseMapper.selectCount(queryWrapper);
        return integer;
    }
}
